package io.kiki.stack.netty.channelManager;

import io.kiki.stack.netty.config.ConfigManager;
import io.kiki.stack.netty.config.Configs;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Random;

/**
 * An implemented strategy to monitor channels:
 * <lu>
 * <li>each time scheduled, filter channels with {@link Configs#CONN_SERVICE_STATUS_OFF} at first.</li>
 * <li>then close channels.</li>
 * </lu>
 */
@Slf4j
@Setter
@Getter
public class ScheduledDisconnectChannelMonitorStrategy implements ChannelMonitorStrategy {

    private final int threshold;
    private final Random random;

    public ScheduledDisconnectChannelMonitorStrategy() {
        this.threshold = ConfigManager.conn_threshold();
        this.random = new Random();
    }


    @Override
    public void monitor(Map<String, RunStateRecordedFutureTask<Pool>> map) {
        try {
            if (map == null || map.size() == 0) {
                return;
            }

            for (Map.Entry<String, RunStateRecordedFutureTask<Pool>> entry : map.entrySet()) {


                List<Channel> serviceOnChannelList = new ArrayList<Channel>();
                List<Channel> serviceOffChannelList = new ArrayList<Channel>();
                Pool pool = RunStateRecordedFutureTask.getFutureTaskResult(entry.getValue());
                for (Channel channel : pool.getAll()) {
                    if (isOn(channel)) {
                        serviceOnChannelList.add(channel);
                    } else {
                        serviceOffChannelList.add(channel);
                    }
                }

                if (serviceOnChannelList.size() > threshold) {
                    Channel channel = serviceOnChannelList.get(random.nextInt(serviceOnChannelList.size()));
                    channel.setAttribute(Configs.CONN_SERVICE_STATUS, Configs.CONN_SERVICE_STATUS_OFF);
                    serviceOffChannelList.add(channel);
                }

                for (Channel channel : serviceOffChannelList) {
                    if (channel.isIdToFutureMapIsEmpty()) {
                        if (channel.isFine()) {
                            channel.close();
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.error("ScheduledDisconnectStrategy monitor error", e);
        }
    }

    private boolean isOn(Channel channel) {
        String serviceStatus = (String) channel.getAttribute(Configs.CONN_SERVICE_STATUS);
        return serviceStatus == null || Boolean.parseBoolean(serviceStatus);
    }
}
